package com.ctsi.commons.util.collections;

import com.ctsi.commons.util.UtilObject;
import com.ctsi.commons.util.UtilValidate;

import java.io.Serializable;
import java.util.*;

/**
 * @author zhangjw
 */
public class UtilCollection {
	public static <T> List<T> unmodifiableList(List<T> list) {
		return (list instanceof RandomAccess ? new UnmodifiableRandomAccessList<T>(list) : new UnmodifiableList<T>(list));
	}

	public static final void removeByPreFix(String prefix, Map<String, ? extends Object> map) {
		if (UtilValidate.isEmpty(map)) {
			return;
		}
		Set<String> keys = map.keySet();
		for (String k : keys) {
			if (k.startsWith(prefix)) {
				map.remove(k);
			}
		}
	}

	/**
	 * 求两个集合的并集
	 * 
	 * @param collection1
	 * @param collection2
	 * @return
	 */
	public static final <T> Collection<T> merge(Collection<? extends T> collection1, Collection<? extends T> collection2) {
		Collection<T> result = new LinkedList<T>(collection1);
		result.removeAll(collection2);
		result.addAll(collection2);
		return result;
	}

	/**
	 * 求多个集合的并集
	 * 
	 * @param allCollection
	 * @return
	 */
	public static final <T> Collection<? extends T> merge(Collection<Collection<? extends T>> allCollection) {
		if (allCollection.size() <= 0) {
			return null;
		}

		Iterator<Collection<? extends T>> it = allCollection.iterator();
		Collection<? extends T> result = it.next();

		while (it.hasNext()) {
			result = merge(result, it.next());
		}
		return result;
	}

	/**
	 * 求多个集合的交集
	 * 
	 * @param allCollection
	 * @return
	 */
	public static final <T> Collection<T> intersection(Collection<Collection<T>> allCollection) {
		if (allCollection.size() <= 0) {
			return null;
		}
		Iterator<Collection<T>> it = allCollection.iterator();
		Collection<T> result = it.next();
		while (it.hasNext()) {
			result = intersection(result, it.next());
		}
		return result;
	}

	/**
	 * 求两个集合的交集
	 * 
	 * @param collection1
	 * @param collection2
	 * @return 返回一个新的集合
	 */
	@SuppressWarnings("unchecked")
	public static final <T> Collection<T> intersection(Collection<T> collection1, Collection<T> collection2) {
		Collection<T> tem;
		if (UtilObject.hasePublicMethod(collection1.getClass(), "clone", UtilObject.emptyClassArray)) {
			tem = (Collection<T>) UtilObject.runMethod(collection1, "clone", UtilObject.emptyObjectArray);
		} else {
			tem = new LinkedList<T>(collection1);
		}

		tem.retainAll(collection2);
		return tem;
	}

	/**
	 * 主要是为了增加一个无参数构造函数
	 * 
	 * @author yueming
	 * 
	 * @param <E>
	 */
	static class UnmodifiableCollection<E> implements Collection<E>, Serializable {

		private static final long serialVersionUID = 1820017752578914078L;

		Collection<E> c;

		protected Collection<E> getData() {
			if (c == null) {
				return Collections.emptyList();
			}
			return c;
		}

		public void setC(Collection<E> c) {
			this.c = c;
		}

		UnmodifiableCollection() {

		}

		UnmodifiableCollection(Collection<E> c) {
			if (c == null) {
				throw new NullPointerException();
			}
			this.c = c;
		}

		@Override
		public int size() {
			return getData().size();
		}

		@Override
		public boolean isEmpty() {
			return getData().isEmpty();
		}

		@Override
		public boolean contains(Object o) {
			return getData().contains(o);
		}

		@Override
		public Object[] toArray() {
			return getData().toArray();
		}

		@Override
		public <T> T[] toArray(T[] a) {
			return getData().toArray(a);
		}

		@Override
		public String toString() {
			return getData().toString();
		}

		@Override
		public Iterator<E> iterator() {
			return new Iterator<E>() {
				private final Iterator<? extends E> i = getData().iterator();

				@Override
				public boolean hasNext() {
					return i.hasNext();
				}

				@Override
				public E next() {
					return i.next();
				}

				@Override
				public void remove() {
					throw new UnsupportedOperationException();
				}
			};
		}

		protected boolean copied;

		protected void copyColl() {
			if (!copied || c == null) {
				if (c != null) {
					c = new LinkedList<E>(c);
				} else {
					c = new LinkedList<E>();
				}
				copied = true;
			}

		}

		@Override
		public boolean add(E e) {
			copyColl();

			return getData().add(e);
		}

		@Override
		public boolean remove(Object o) {
			copyColl();
			return getData().remove(o);
		}

		@Override
		public boolean containsAll(Collection<?> coll) {
			return getData().containsAll(coll);
		}

		@Override
		public boolean addAll(Collection<? extends E> coll) {
			copyColl();
			return getData().addAll(coll);
		}

		@Override
		public boolean removeAll(Collection<?> coll) {
			copyColl();
			return getData().removeAll(coll);
		}

		@Override
		public boolean retainAll(Collection<?> coll) {
			copyColl();
			return getData().removeAll(coll);
		}

		@Override
		public void clear() {
			copyColl();
			getData().clear();
		}

	}

	static class UnmodifiableList<E> extends UnmodifiableCollection<E> implements List<E> {
		private static final long serialVersionUID = -283967356065247728L;
		List<E> list;

		UnmodifiableList() {

		}

		UnmodifiableList(List<E> list) {
			super(list);
			this.list = list;
		}

		@Override
		protected void copyColl() {
			if (!copied || list == null) {
				if (list != null) {
					list = new ArrayList<E>(list);
				} else {
					list = new ArrayList<E>();
				}

				copied = true;
			}
		}

		@Override
		protected Collection<E> getData() {
			if (list == null) {
				return Collections.emptyList();
			}
			return list;
		}

		@Override
		public boolean equals(Object o) {
			return o == this || list.equals(o);
		}

		@Override
		public int hashCode() {
			return list.hashCode();
		}

		@Override
		public E get(int index) {
			return list.get(index);
		}

		@Override
		public E set(int index, E element) {
			copyColl();
			return list.set(index, element);
		}

		@Override
		public void add(int index, E element) {
			copyColl();
			list.add(index, element);
		}

		@Override
		public E remove(int index) {
			copyColl();
			return list.remove(index);
		}

		@Override
		public int indexOf(Object o) {
			return list.indexOf(o);
		}

		@Override
		public int lastIndexOf(Object o) {
			return list.lastIndexOf(o);
		}

		@Override
		public boolean addAll(int index, Collection<? extends E> c) {
			copyColl();
			return list.addAll(index, c);

		}

		@Override
		public ListIterator<E> listIterator() {
			return listIterator(0);
		}

		@Override
		public ListIterator<E> listIterator(final int index) {
			return new ListIterator<E>() {
				private final ListIterator<? extends E> i = list.listIterator(index);

				@Override
				public boolean hasNext() {
					return i.hasNext();
				}

				@Override
				public E next() {
					return i.next();
				}

				@Override
				public boolean hasPrevious() {
					return i.hasPrevious();
				}

				@Override
				public E previous() {
					return i.previous();
				}

				@Override
				public int nextIndex() {
					return i.nextIndex();
				}

				@Override
				public int previousIndex() {
					return i.previousIndex();
				}

				@Override
				public void remove() {
					throw new UnsupportedOperationException();
				}

				@Override
				public void set(E e) {
					throw new UnsupportedOperationException();
				}

				@Override
				public void add(E e) {
					throw new UnsupportedOperationException();
				}
			};
		}

		@Override
		public List<E> subList(int fromIndex, int toIndex) {
			return new UnmodifiableList<E>(list.subList(fromIndex, toIndex));
		}

		/**
		 * UnmodifiableRandomAccessList instances are serialized as UnmodifiableList instances to allow them to be deserialized in pre-1.4 JREs (which do not
		 * have UnmodifiableRandomAccessList). This method inverts the transformation. As a beneficial side-effect, it also grafts the RandomAccess marker onto
		 * UnmodifiableList instances that were serialized in pre-1.4 JREs.
		 * 
		 * Note: Unfortunately, UnmodifiableRandomAccessList instances serialized in 1.4.1 and deserialized in 1.4 will become UnmodifiableList instances, as
		 * this method was missing in 1.4.
		 */
		private Object readResolve() {
			return (list instanceof RandomAccess ? new UnmodifiableRandomAccessList<E>(list) : this);
		}
	}

	static class UnmodifiableRandomAccessList<E> extends UnmodifiableList<E> implements RandomAccess {
		UnmodifiableRandomAccessList(List<E> list) {
			super(list);
		}

		UnmodifiableRandomAccessList() {

		}

		@Override
		public List<E> subList(int fromIndex, int toIndex) {
			return new UnmodifiableRandomAccessList<E>(list.subList(fromIndex, toIndex));
		}

		private static final long serialVersionUID = -2542308836966382001L;

		/**
		 * Allows instances to be deserialized in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList). UnmodifiableList has a readResolve method that
		 * inverts this transformation upon deserialization.
		 */
		private Object writeReplace() {
			return new UnmodifiableList<E>(list);
		}
	}
}
